#include "tcp.h"

using namespace std;

tcp::tcp(QWidget *parent):
    QWidget (parent)
{
    log("I am tcp");
    this->tcpSocket = new QTcpSocket(this);

    this->cnt = 0;
    this->step = 0;

    //socket添加信号槽函数
    connect(tcpSocket,&QTcpSocket::readyRead,
            this,&tcp::onReadMessage);

    connect(tcpSocket, &QTcpSocket::connected, this, &tcp::connected);
}

uint8_t tcp::linkSever()
{
    //清除所有连接
    tcpSocket->abort();

    QByteArray ba = host.toLatin1();

    log("正在连接%s,端口:%d", ba.data(), post);

    //连接服务端
    tcpSocket->connectToHost(host, post);

    tcpSocket->waitForConnected(1000);
    log("连接服务器调用完毕");

    return 0;
}

void tcp::connected()
{
    qDebug() << "连接成功";
    this->tx_uint8(A_JOIN_SERVER_ID, 1);
}

void tcp::onReadMessage()
{
    QByteArray bt;
    bt.resize(tcpSocket->bytesAvailable());
    tcpSocket->read(bt.data(),bt.size());

    char *data = bt.data();
    int len = bt.size();

    //打印出数据
    qDebug()<<bt<<"len:"<<len;

    for (int i=0; i < len; i++) {
        analysis((uint8_t)data[i]);
    }
}

/**
 * @brief  根据上位机命令做出对应响应
 * @param  void
 * @retval void
 */
void tcp::DeerSwitch(void)
{
    switch(this->buff[3])
    {
        case A_JOIN_SERVER_SUCCEED_ID:		/* 发送给我的ID */
            union{
                uint8_t u8[2];
                uint16_t u16;
            } u16_u8;

            u16_u8.u8[0] = this->buff[5];
            u16_u8.u8[1] = this->buff[4];

            qDebug()<<u16_u8.u16;

            this->get_id(u16_u8.u16);

            break;
    case A_POST_CREATE_HOUSE:		/* 发送给我的ID */
        this->creater_succeed();
        break;
    case A_POST_GET_HOUSE:		/* 列表 */
        {
            union{
                uint8_t u8[2];
                uint16_t u16;
            } u16_u8;

            u16_u8.u8[0] = this->buff[5];
            u16_u8.u8[1] = this->buff[4];

            qDebug()<<u16_u8.u16;

            list_addItem(u16_u8.u16, QString::fromUtf8((char *)&this->buff[6]));
            break;
        }
    case A_JOIN_ROOM_SUCCEED_ID:
        {
            union{
                uint8_t u8[2];
                uint16_t u16;
            } u16_u8;

            u16_u8.u8[0] = this->buff[5];
            u16_u8.u8[1] = this->buff[4];

            join_succeed(u16_u8.u16);
            break;
        }
    case A_TELL_DATA:
        {
            qDebug()<<this->buff;
            break;
        }
    case A_TELL_STRING:
        {
            this->rx_string(QString::fromUtf8((char *)&this->buff[4]));

            break;
        }
    case A_TELL_POS_XY:
            this->rx_pos_xy(this->buff[4], this->buff[5], (char)this->buff[6]);
            log("收到下棋信息x:%d, y:%d, color:%d", this->buff[4], this->buff[5], (char)this->buff[6]);
            break;
    case A_TELL_COLOR:
        this->rx_color((char)this->buff[4]);
        break;
    case A_GET_VERSION:
        this->rx_version(this->buff[4]);
        qDebug()<<"版本:"<<buff[4];
        break;
    case A_TELL_UNDO:
        this->rx_undo();
        break;
    case A_TELL_UNDORX:
        this->rx_undo_state(buff[4]);
        break;
    }
}

/**
* @brief  上位机指令解析
 * @param  void
 * @retval void
 */
void tcp::DeerParsing(void)
{
    uint8_t ack = 0;

    for (int i=0; i < this->rxlen; i++) {
        ack += this->buff[i];
    }

    if (ack == this->buff[this->rxlen]) {
        this->DeerSwitch();
    }
}

void tcp::analysis(uint8_t date)
{

    switch(this->step) {
        case 0:
            this->cnt = 0;
            this->buff[this->cnt++] = date;
            if (date == 0xFD) {
                this->step = 1;
            }
            break;
        case 1:
            this->buff[this->cnt++] = date;
            if (date == 0xDF) {
                this->step = 2;
            } else {
                this->step = 0;
            }
            break;
        case 2:
            this->buff[this->cnt++] = date;

            if (this->cnt - 1 == 2) {
                this->rxlen = date;
            }

            if (this->cnt > this->rxlen) {
                this->step = 3;
                this->cnt = 0;
            }

            break;

        default :
        {};
    }

    if (this->step == 3) {
        this->step = 0;
        this->DeerParsing();
    }

}

/**
 * @brief  通信发送底层函数
 * @param  void
 * @retval void
 */
void tcp::tx(uint8_t fun, uint16_t fd, uint8_t *date, uint8_t datelen)
{
    uint8_t SendBuff[70];
    uint8_t len = 0;

    if (datelen >= 70) {
        return;
    }

    /* 帧头 */
    SendBuff[len++] = 0xFD;
    SendBuff[len++] = 0xDF;

    /* 总长度 先占位 */
    SendBuff[len++] = 0;

    /* 功能帧 */
    SendBuff[len++] = fun;

    /* fd设备帧 */
    SendBuff[len++] = (fd&0xff00)>>8;
    SendBuff[len++] = fd&0x00ff;

    /* 数据 */
    for (int max = (datelen + len), now = len; len < max; len++) {
        SendBuff[len] = date[len - now];
    }

    /* 获取实际长度 */
    SendBuff[2] = len;

    /* 校验位 */
    SendBuff[len] = 0;
    for (int i = 0; i < len; i++) {
        SendBuff[len] += SendBuff[i];
    }

    //log("len:%d", len);
    tcpSocket->flush();//清空缓冲区
    tcpSocket->write((const char *)SendBuff, len+1);
    tcpSocket->waitForBytesWritten(1000);
    //err("发送成功%d");
}

/**
 * @brief  通信发送底层函数
 * @param  void
 * @retval void
 */
void tcp::tx(uint8_t fun, uint8_t *date, uint8_t datelen)
{
    uint8_t SendBuff[70];
    uint8_t len = 0;

    /* 帧头 */
    SendBuff[len++] = 0xFD;
    SendBuff[len++] = 0xDF;

    /* 总长度 先占位 */
    SendBuff[len++] = 0;

    /* 功能帧 */
    SendBuff[len++] = fun;

    /* 数据 */
    for (int max = (datelen + len), now = len; len < max; len++) {
        SendBuff[len] = date[len - now];
    }

    /* 获取实际长度 */
    SendBuff[2] = len;

    /* 校验位 */
    SendBuff[len] = 0;
    for (int i = 0; i < len; i++) {
        SendBuff[len] += SendBuff[i];
    }

    tcpSocket->flush();//清空缓冲区
    tcpSocket->write((const char *)SendBuff, len+1);
    tcpSocket->waitForBytesWritten(1000);

    //err("发送成功");
}

/**
 * @brief  发送16位数据
 * @param  void
 * @retval void
 */
void tcp::tx_uint8(uint8_t fun, uint8_t date)
{
    this->tx(fun, &date, 1);
}

/**
 * @brief  发送16位数据
 * @param  void
 * @retval void
 */
void tcp::tx_uint16(uint8_t fun, uint16_t date)
{
    uint8_t txdate[2];
    txdate[0] = (uint8_t)(date >> 8);
    txdate[1] = (uint8_t)date;

    this->tx(fun, txdate, 2);
}
